/**
 * Title: base Json parser
 * Description: define commonly used for Json base communication.
 * Copyright: Copyright (c) 2013 Kugou (All rights reserved)
 * Company: Kugou
 * Author: zhiguangq
 * Reviser: <Please input reviser>
 * Date: 2013-9-24
 * Version: 1.0
 * History: [1.0 2013-9-24]
 */
 
#ifndef JSON_FACILITY_BASE_KUGOU_H
#define JSON_FACILITY_BASE_KUGOU_H

#include <vector>
#include <utility>
#include <iterator>
#include <boost/foreach.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#define JSON_NAME_TOSTRING(name) #name
#define JSON_ADD_PARA(name) generic_json_parser(JSON_NAME_TOSTRING(name), name, m_pt, m_curOper)

#define smart_ptr boost::shared_ptr

namespace kugou
{
namespace base
{
namespace facility
{

enum OperType
{ 
	ToJson,  // Convert object to json string
	FromJson // Parse json string to object.
};

class Json
{
public:
	Json(){}

	virtual ~Json(){}

	/**
	 * save json data to a string.
	 *
	 * @return The json data string.
	 */
	std::string toJson(void);

	/**
	 * save json data to a file.
	 *
	 * @return write file success or not
	 */
	bool toJson(const std::string& fileName);

	/**
	 * load json data from a string.
	 *
	 * @return str input json data string.
	 */
	void fromJson(const std::string& str);

	/**
	 * load json data from a file.
	 *
	 * @return str input json data string.
	 */
    bool fromJsonFile(const std::string& fileName);

protected:
	/**
	 * load json data from ptree.
	 *
	 * @return str input json data string.
	 */
	void fromJson(const boost::property_tree::ptree& pt);

	operator boost::property_tree::ptree()
	{
		m_curOper = ToJson;
		assign();
		return m_pt;
	}

	template<class T>
	void generic_json_parser(const char* name, T& t, boost::property_tree::ptree& pt, OperType oper)
	{
		if (FromJson == oper)
		{
			t = pt.get<T>(name);
		}
		else
		{
			pt.put<T>(name, t);
		}
	}

	template<class T>
	void generic_json_parser(const char* name, smart_ptr<T>& t, boost::property_tree::ptree& pt, OperType oper)
	{
		if (FromJson == oper)
		{
			if ((bool)pt.get_optional<T>(name))
			{
				t.reset(new T());
				*t = pt.get<T>(name);
			}
		}
		else
		{
			if (t)
			{
				pt.put<T>(name, *t);
			}
		}
	}

	template<typename T>
	void generic_json_parser(const char* name, std::vector<T>& t, boost::property_tree::ptree& pt, OperType oper)
	{
		if (FromJson == oper)
		{
			if ((bool)pt.get_child_optional(name))
			{
				BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pt.get_child(name))
				{
					 T item;
					 item.fromJson(v.second);
					 t.push_back(item);
				}
			}
		}
		else
		{
			boost::property_tree::ptree arr;
			for (typename std::vector<T>::iterator iter = t.begin(); iter != t.end(); ++iter)
			{
				arr.push_back(std::make_pair("", (boost::property_tree::ptree)(*iter)));
			}
			if (!t.empty())
			{
				pt.put_child(name, arr);
			}
		}
	}

	template<typename T>
	void json_parser_base_type(const char* name, std::vector<T>& t, boost::property_tree::ptree& pt, OperType oper)
	{
		if (FromJson == oper)
		{
			if((bool)pt.get_child_optional(name))
			{
				BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pt.get_child(name))
				{
					t.push_back(v.second.get_value<T>());
				}
			}
		}
		else
		{
			boost::property_tree::ptree arr;
			for(typename std::vector<T>::iterator iter = t.begin(); iter != t.end(); ++iter)
			{
				boost::property_tree::ptree item;
				item.put_value(*iter);
				arr.push_back(make_pair("", item));
			}
			if (!t.empty())
			{
				pt.put_child(name, arr);
			}
		}
	}

	void generic_json_parser(const char* name, std::vector<int>& t, boost::property_tree::ptree& pt, OperType oper)
	{
		json_parser_base_type(name, t, pt, oper);
	}

	template<typename T>
	void generic_json_parser(const char* name, std::vector<smart_ptr<T> >& t, boost::property_tree::ptree& pt, OperType oper)
	{
		if (FromJson == oper)
		{
			if((bool)pt.get_child_optional(name))
			{
				BOOST_FOREACH(boost::property_tree::ptree::value_type &v, pt.get_child(name))
				{
					t.push_back(boost::shared_ptr<T>(new T(v.second.get_value<T>())));
				}
			}
		}
		else
		{
			boost::property_tree::ptree arr;
			for(typename std::vector<smart_ptr<T> >::iterator iter = t.begin(); iter != t.end(); ++iter)
			{
				boost::property_tree::ptree item;
				item.put_value(**iter);
				arr.push_back(make_pair("", item));
			}
			if (!t.empty())
			{
				pt.put_child(name, arr);
			}
		}
	}

	OperType m_curOper;
    boost::property_tree::ptree m_pt;

    virtual void assign()
    {
    }
};

} // facility
} // base
} // kugou

#endif 
